#ifndef AE_H
#define AE_H
#ifdef __cplusplus
extern "C" {
#endif

#define AE_ADDRESS_ANY    "0.0.0.0"
#define AE_ADDRESS_ANY6   "::0"
#define AE_ADDRESS_LOCAL  "127.0.0.1"
#define AE_ADDRESS_LOCAL6 "::1"
#define AE_ADDRESS_STRLEN 55
#ifdef AE_ONLY_IPV4
#define AE_ADDRESS_SIZE 16
#else
#define AE_ADDRESS_SIZE 28
#endif

enum {
	AE_TYPE_IN,
	AE_TYPE_OUT
};

enum {
	AE_POLL_ERROR    = 1,
	AE_POLL_READ     = (1<<1),
	AE_POLL_WRITE    = (1<<2),
	AE_POLL_HANGUP   = (1<<3),
	AE_POLL_RCVTIMEO = (1<<4),
	AE_POLL_SNDTIMEO = (1<<5)
};

typedef long long ae_time_t;
typedef struct {int __noused;}* ae_object_t;
typedef struct {char __pad[AE_ADDRESS_SIZE];} ae_address_t;

int ae_startup();
int ae_cleanup();

ae_time_t ae_timestamp(ae_time_t*);

int ae_poll_create(ae_object_t* poll);
int ae_poll_destory(ae_object_t poll);
int ae_poll_attach(ae_object_t poll, ae_object_t object, void* context);
int ae_poll_wait(ae_object_t poll, ae_object_t *object, int *events, void** context, int milliseconds);

int ae_address_ip(ae_address_t* addr, char* ip, int size);
int ae_address_port(ae_address_t* addr, unsigned short* port);
int ae_address_string(ae_address_t* addr, char* address, int size);
int ae_address_query4(ae_address_t* addr, const char* netname, unsigned short port, int address_size);
#define ae_address_query(a, n, p) ae_address_query4(a, n, p, AE_ADDRESS_SIZE)

int ae_socket_close(ae_object_t sock);
int ae_socket_sync_timeout(ae_object_t sock, int seconds, int type);
int ae_socket_async_timeout(ae_object_t sock, int seconds, int type);

int ae_stream_listen(ae_object_t* sock, const ae_address_t* addr, int backlog);
int ae_stream_accept(ae_object_t sock, ae_object_t* child);
int ae_stream_connect(ae_object_t* sock, const ae_address_t* addr);
int ae_stream_recv(ae_object_t sock, void* buffer, int size);
int ae_stream_send(ae_object_t sock, const void* buffer, int size);
int ae_stream_address(ae_object_t sock, ae_address_t* peer, ae_address_t* local);
int ae_stream_nodelay(ae_object_t sock, int nodelay);
int ae_stream_keeplive(ae_object_t sock, int onoff, int idle, int interval);

int ae_dgram_bind(ae_object_t* sock, const ae_address_t* addr);
int ae_dgram_recv(ae_object_t sock, void* buffer, int size, ae_address_t* source);
int ae_dgram_send(ae_object_t sock, const void* buffer, int size, ae_address_t* target);
int ae_dgram_multicast(ae_object_t sock, const ae_address_t* addr, int join_or_leave);
int ae_dgram_multicast_ttl(ae_object_t sock, int ttl);
int ae_dgram_multicast_loop(ae_object_t sock, int loop);

#ifdef __cplusplus
}
#endif
#endif
